#pragma once

#include<BWAPI.h>
#include<string>

using namespace BWAPI;
using namespace std;

string AttackStateStrings[] = {"NotAttack" , "MoveToTarget" , "WaitForAttack" , "Attacking"};

class ControlerBase
{
public:
	enum State{UnKnown , AttackUnit};
	enum AttackState{NotAttack , MoveToTarget , WaitForAttack , Attacking};
	ControlerBase(Unit* unitToControl)
		:_unitToControl(unitToControl),
		_state(UnKnown),
		_attackState(NotAttack),
		_target(NULL),
		_lastMoveFrame(-1),
		_lastAttackFrame(-1)
	{
	}
	virtual void OnFrame()
	{
		if(_state == AttackUnit)
		{
			if(_target->getHitPoints() <= 0)
			{
				_state = UnKnown;
				_attackState = NotAttack;
				_target = NULL;
				return;
			}

			int frameNow = Broodwar->getFrameCount();
			double distance = _target->getPosition().getDistance(_unitToControl->getPosition());
			double interval = distance / _unitToControl->getType().topSpeed();
			if(interval <= 6){interval = 6;}
			if(_attackState == MoveToTarget)
			{
				if(_target->getDistance(_unitToControl) <= _unitToControl->getType().groundWeapon().maxRange())
				{
					_attackState = WaitForAttack;
				}
				else
				{
					if(frameNow - _lastMoveFrame >= 6 && frameNow - _lastAttackFrame >= 9)
					{
						Position targetFuturePosition = GetFuturePosition(_target , interval);
						_unitToControl->move(targetFuturePosition);
						_lastMoveFrame = frameNow;
					}
				}
			}
			else if(_attackState == WaitForAttack)
			{
				if(frameNow - _lastMoveFrame >= 6 && frameNow - _lastAttackFrame >= 9)
				{
					_unitToControl->attack(_target);
					_attackState = Attacking;
					_lastAttackFrame = frameNow;
				}
			}
			else if(_attackState == Attacking)
			{
				if(_target->getDistance(_unitToControl) > _unitToControl->getType().groundWeapon().maxRange())
				{
					_attackState = MoveToTarget;
				}
			}

		}
	}
	bool IsDead() const
	{
		return _unitToControl->getHitPoints() <= 0;
	}
	Unit* GetControllingUnit() const
	{
		return _unitToControl;
	}
	virtual void Attack(Unit* target)
	{
		_target = target;
		_state = AttackUnit;
		_attackState = MoveToTarget;
	}
protected:
	Position GetFuturePosition(Unit* whichUnit , int frameCount) const
	{
		double interval = frameCount;
		double offsetX = whichUnit->getVelocityX() * interval;
		double offsetY = whichUnit->getVelocityY() * interval;
		return whichUnit->getPosition() + Position(offsetX , offsetY);
	}
	Unit* _unitToControl;
	State _state;
	AttackState _attackState;
	Unit* _target;
	int _lastAttackFrame;
	int _lastMoveFrame;
};